<?php
/**
 * PureMVC Port to PHP originally translated by Asbjørn Sloth Tønnesen
 *
 * @author Omar Gonzalez :: omar@almerblank.com
 * @author Hasan Otuome :: hasan@almerblank.com
 *
 * Created on Sep 24, 2008
 * PureMVC - Copyright(c) 2006-2008 Futurescale, Inc., Some rights reserved.
 * Your reuse is governed by the Creative Commons Attribution 3.0 Unported License
 */

/**
 * A Singleton <code>IController</code> implementation.
 *
 * <P>
 * In PureMVC, the <code>Controller</code> class follows the
 * 'Command and Controller' strategy, and assumes these
 * responsibilities:
 * <UL>
 * <LI> Remembering which <code>PureMVC_Command_Interface</code>s
 * are intended to handle which <code>PureMVC_Observer_Notification_Interfaces</code>.</LI>
 * <LI> Registering itself as an <code>PureMVC_Observer_Interface</code> with
 * the <code>View</code> for each <code>PureMVC_Observer_Notification_Interface</code>
 * that it has an <code>PureMVC_Command_Interface</code> mapping for.</LI>
 * <LI> Creating a new instance of the proper <code>PureMVC_Command_Interface</code>
 * to handle a given <code>PureMVC_Observer_Notification_Interface</code> when notified by the <code>View</code>.</LI>
 * <LI> Calling the <code>PureMVC_Command_Interface</code>'s <code>execute</code>
 * method, passing in the <code>PureMVC_Observer_Notification_Interface</code>.</LI>
 * </UL>
 *
 * <P>
 * Your application must register <code>PureMVC_Command_Interfaces</code> with the
 * Controller.
 * <P>
 * The simplest way is to subclass </code>PureMVC_Facade</code>,
 * and use its <code>initializeController</code> method to add your
 * registrations.
 *
 * @package org.puremvc.php.core.Controller
 * @see org.puremvc.core.View View
 * @see org.puremvc.php.patterns.observer.Observer Observer
 * @see org.puremvc.php.patterns.observer.Notification Notification
 * @see org.puremvc.php.patterns.command.SimpleCommand SimpleCommand
 * @see org.puremvc.php.patterns.command.MacroCommand MacroCommand
 */
class PureMVC_Controller implements PureMVC_Controller_Interface
{

	// Local reference to View
	protected $_view;

	// Mapping of Notification names to Command Class references
	protected $_commandMap;

	// Singleton instance
	protected static $_instance;

	/**
	 * Constructor.
	 *
	 * <P>
	 * This <code>IController</code> implementation is a Singleton,
	 * so you should not call the constructor
	 * directly, but instead call the static Singleton
	 * Factory method <code>Controller.getInstance()</code>
	 *
	 * @throws Error Error if Singleton instance has already been constructed
	 *
	 */
	private function __construct()
	{
		$this->_commandMap = array();
		$this->_initializeController();
	}

	/**
	 * Initialize the Singleton <code>Controller</code> instance.
	 *
	 * <P>Called automatically by the constructor.</P>
	 *
	 * <P>Note that if you are using a subclass of <code>View</code>
	 * in your application, you should <i>also</i> subclass <code>Controller</code>
	 * and override the <code>initializeController</code> method in the
	 * following way:</P>
	 *
	 * <listing>
	 *		// ensure that the Controller is talking to my PureMVC_View_Interface implementation
	 *		override public function initializeController(  ) : void
	 *		{
	 *			view = MyView.getInstance();
	 *		}
	 * </listing>
	 *
	 * @return void
	 */
	protected function _initializeController()
	{
		$this->_view = PureMVC_View::getInstance();
	}

	/**
	 * <code>Controller</code> Singleton Factory method.
	 *
	 * @return the Singleton instance of <code>Controller</code>
	 */
	public static function getInstance()
	{
		if ( self::$_instance == null )
			self::$_instance = new self( );
		return self::$_instance;
	}

	/**
	 * If an <code>PureMVC_Command_Interface</code> has previously been registered
	 * to handle a the given <code>PureMVC_Observer_Notification_Interface</code>, then it is executed.
	 *
	 * @param note an <code>PureMVC_Observer_Notification_Interface</code>
	 */
	public function executeCommand( PureMVC_Observer_Notification_Interface $note )
	{
		$commandClassName = $this->_commandMap[ $note->getName() ];
		//TODO: send bug report
		if ( !empty( $commandClassName ) )
		{
			$commandClassReflector = new ReflectionClass( $commandClassName );
			$commandClassRef = $commandClassReflector->newInstance();
			$commandClassRef->execute( $note );
		}
	}

	/**
	 * Register a particular <code>PureMVC_Command_Interface</code> class as the handler
	 * for a particular <code>PureMVC_Observer_Notification_Interface</code>.
	 *
	 * <P>
	 * If an <code>PureMVC_Command_Interface</code> has already been registered to
	 * handle <code>PureMVC_Observer_Notification_Interface</code>s with this name, it is no longer
	 * used, the new <code>PureMVC_Command_Interface</code> is used instead.</P>
	 *
	 * @param notificationName the name of the <code>PureMVC_Observer_Notification_Interface</code>
	 * @param commandClassRef the <code>Class</code> of the <code>PureMVC_Command_Interface</code>
	 */
	public function registerCommand( $notificationName, $commandClassRef )
	{
		$this->_commandMap[ $notificationName ] = $commandClassRef;
		$this->_view->registerObserver( $notificationName, new PureMVC_Observer( "executeCommand", $this ) );
	}
	/**
	 * Check if a Command is registered for a given Notification
	 *
	 * @param string $notificationName
	 * @return whether a Command is currently registered for the given <code>notificationName</code>.
	 */
	public function hasCommand( $notificationName )
	{
		return $this->_commandMap[ $notificationName ] != null;
	}

	/**
	 * Remove a previously registered <code>PureMVC_Command_Interface</code> to <code>PureMVC_Observer_Notification_Interface</code> mapping.
	 *
	 * @param notificationName the name of the <code>PureMVC_Observer_Notification_Interface</code> to remove the <code>PureMVC_Command_Interface</code> mapping for
	 */
	public function removeCommand( $notificationName )
	{
		$this->_commandMap[ $notificationName ] = null;
	}
}

